from django.contrib.auth.forms import get_user_model
from django.contrib.contenttypes.fields import GenericRelation
from django.shortcuts import reverse
from django.utils.translation import gettext_lazy as _
from django.db import models
from django.conf import settings
from audit.models import AuditManagement, AUDIT_STATUS
from lib.django import models as mymodels
from django.apps import apps

class Project(models.Model):
    class MedicineCategory(models.TextChoices):
        TRADIRIONAL_CHINESE = "traditional-chinese", _("中药")
        CHEMICAL = "chemical", _("化学药")
        PREVENTIVE_BIOLOGICAL = "preventive-biological", _("预防用生物制品")
        THERAPEUTIC_BIOLOGICAL = "therapeutic-biological", _("治疗用生物制品")
        IVD_REAGENTS = "IVD-reagents", _("按生物制品管理的体外诊断试剂")
        Other = "Other", _("其它")

    class SponsorTypeChoices(models.TextChoices):
        ForeignCompany = "foreign_ompany", _("外企")
        BeijingEnterprise = "beijing_enterprise", _("京企")
        HMT = "hmt", _("港澳台")
        OtherCompany = "other_company ", _("其它内资企业")

    class AUDIT_PROGRESS(models.IntegerChoices):
        BEGIN          = 0, _("开始审核")
        INFO           = 1, _("项目信息审核通过")
        PLAN           = 2, _("项目方案审核通过")
        INITIATION     = 3, _("项目立项资料审核通过")
        BEFORE_PROJECT = 4, _("项目启动前审核通过")
        IMPLEMENT      = 5, _("项目入组审核通过")
        FINISHED       = 6, _("项目结束审核通过")

    chinese_name = models.CharField(verbose_name=_("项目中文名称"), max_length=1000)
    english_name = models.CharField(verbose_name=_("项目英文名称"), max_length=1024)
    creator = models.ForeignKey(
        to=settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        editable=False,
        verbose_name=_("项目创建者")
    )

    drug_name = models.CharField(
        verbose_name=_("药物名称"), max_length=1000, blank=True, default=""
    )
    device_name = models.CharField(
        verbose_name=_("器械名称"), max_length=255, blank=True, default=""
    )
    is_innovative_drug_device = mymodels.YesNoField(verbose_name=_("创新药械"), default=False)
    clinical_trial_approval_number = models.CharField(
        verbose_name=_("临床试验批件编号"), max_length=255, blank=True, default=""
    )
    registration_publicity_number = models.CharField(
        verbose_name=_("默许备案公示编号"), max_length=255, blank=True, default=""
    )
    clinical_trial_notification_number = models.CharField(
        verbose_name=_("临床试验通知书编号"), max_length=255, blank=True, default=""
    )
    new_drug_certificate_number = models.CharField(
        verbose_name=_("新药证书编号"), max_length=512, blank=True, default=""
    )
    approval_date = models.DateField(
        verbose_name=_("批准时间"), null=True, blank=True, default=None
    )
    device_trial_approval_doc_name = models.CharField(
        verbose_name=_("器械类临床试验批准文件名称"),
        max_length=512,
        blank=True,
        default="",
    )
    device_trial_approval_doc_number = models.CharField(
        verbose_name=_("器械类临床试验批准文件编号"),
        max_length=512,
        blank=True,
        default="",
    )
    device_trial_approval_unit = models.CharField(
        verbose_name=_("器械类临床试验批准单位"), max_length=512, blank=True, default=""
    )
    special_notes = models.CharField(
        verbose_name=_("项目特殊说明"),
        max_length=512,
        blank=True,
        default="",
        help_text=_(
            "例如：进入国家优先审批通道的医疗器械项目（含诊断试剂、医学人工智能产品），"
            "治疗罕见病/儿童疾病的北京企业品种项目等"
        ),
    )
    specialty_type = models.CharField(
        verbose_name=_("专业"),
        max_length=128,
        blank=True,
        default="",
        help_text=_("选项：精神、戒毒、I期、其他（请描述）"),
    )
    drug_category = models.CharField(
        verbose_name=_("药物类别"),
        max_length=32,
        choices=MedicineCategory.choices,
        default=MedicineCategory.TRADIRIONAL_CHINESE,
        help_text=_(
            "药物类别”应根据实际情况选择“中药”、“化学药”、“预防用生物制品”、"
            "“治疗用生物制品”、“按生物制品管理的体外诊断试剂”。"
        ),
    )
    drug_category_other_description = models.TextField(
        verbose_name="药物其它类型说明",
        max_length=1000,
        blank=True,
        default="",
        help_text=_("药物其它类型说明"),
    )
    registration_class = models.CharField(
        verbose_name=_("注册分类"),
        max_length=128,
        blank=True,
        default="",
        help_text=_("注册分类”请按照申报的注册分类填写，如化学药品1.1类等"),
    )
    trial_phase = models.CharField(
        verbose_name=_("试验类型"),
        max_length=128,
        blank=True,
        default="",
        help_text=_(
            "试验类型”应选择Ⅰ期、Ⅱ期、Ⅲ期、Ⅳ期、生物等效性试验，其他（请说明）"
        ),
    )
    device_clinical_trial_type = models.CharField(
        verbose_name=_("器械临床试验"), max_length=1024, blank=True, default=""
    )
    project_origin = models.CharField(
        verbose_name=_("项目来源"),
        max_length=128,
        blank=True,
        default="",
        help_text=_("项目来源”应根据注册申请单位所在地选择“北京”、“外省市”或“境外”"),
    )
    is_generic_consistency_evaluation = mymodels.YesNoField(
        verbose_name=_("仿制药质量和疗效一致性评价品种"),
        default=False,
    )
    is_lead_center = mymodels.YesNoField(
        verbose_name=_("组长单位"),
        default=False,
    )
    lead_center_name = models.CharField(
        verbose_name=_("组长单位名称"), max_length=500, blank=True, default=""
    )
    is_domestic_multicenter = mymodels.YesNoField(
        verbose_name=_("国内"),
        default=False,
    )
    is_international_multicenter = mymodels.YesNoField(
        verbose_name=_("国际"),
        default=False,
    )

    is_imported_registration = mymodels.YesNoField(
        verbose_name=_("进口注册品种"),
        default=False,
    )
    is_epidemic_control = mymodels.YesNoField(
        verbose_name=_("是否为疫情防控用品种"),
        default=False,
    )

    is_single_center = mymodels.YesNoField(
        verbose_name=_("是否是单中心"),
        default=False,
        help_text=_("否则则是多中心")
    )

    participating_centers_names = models.TextField(
        verbose_name=_("全部参与中心名称"),
        blank=True,
        default="",
        help_text=_("名字之间可以用逗号"),
    )
    national_regional_lead_investigator = models.CharField(
        verbose_name=_("项目全国/区域牵头PI"),
        max_length=512,
        blank=True,
        default="",
        help_text=_("名字之间可以用逗号"),
    )
    site_principal_investigator = models.CharField(
        verbose_name=_("本单位PI"),
        max_length=255,
        blank=True,
        default="",
        help_text=_("名字之间可以用逗号"),
    )
    site_coordinator_contact = models.CharField(
        verbose_name=_("项目本单位协调员及联系电话"),
        max_length=255,
        blank=True,
        default="",
    )
    
    authorized_researchers = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        limit_choices_to={"is_researcher": True},
        blank=True,
        related_name='authorized_projects',
        verbose_name=_("授权研究者"),
    ) 
    
    sponsor_name = models.CharField(
        verbose_name=_("申办方（中英文）"), max_length=512, blank=True, default=""
    )
    sponsor_type = models.CharField(
        verbose_name=_("申办方类型"),
        max_length=32,
        choices=SponsorTypeChoices.choices,
        default=SponsorTypeChoices.OtherCompany,
    )
    cro_name = models.CharField(
        verbose_name=_("CRO（中英文）"), max_length=512, blank=True, default=""
    )
    smo_name = models.CharField(
        verbose_name=_("SMO（中英文）"), max_length=512, blank=True, default=""
    )
    partner_name = models.CharField(
        verbose_name=_("合作方"), max_length=1000, blank=True, default=""
    )
    nhc_registration_number = models.CharField(
        verbose_name=_("卫健委网站备案号"), max_length=1000, blank=True, default=""
    )
    nmpa_registration_number = models.CharField(
        verbose_name=_("药监局网站备案号"), max_length=1000, blank=True, default=""
    )
    project_manager_contact = models.CharField(
        verbose_name=_("项目经理及联系电话"), max_length=255, blank=True, default=""
    )
    cra_contact = models.CharField(
        verbose_name=_("CRA及联系电话"), max_length=255, blank=True, default=""
    )
    crc_contact = models.CharField(
        verbose_name=_("CRC及联系电话"), max_length=255, blank=True, default=""
    )
    is_in_crc_cra_group = mymodels.YesNoField(
        verbose_name=_("进入”北大六院项目CRC.CRA群”"), default=False
    )
    who_registration_number = models.CharField(
        verbose_name=_("WHO临床试验登记网站注册号"),
        max_length=255,
        blank=True,
        default="",
        help_text=_("WHO临床试验登记网站注册号（www.chictr.org.cn）"),
    )
    project_initiation_date = models.DateField(
        verbose_name=_("机构立项时间"), null=True, blank=True, default=None
    )
    # plan_discuss = models.OneToOneField(to=PlanDiscussion, null=True, on_delete=models.SET_NULL, blank=True,
    #                                     verbose_name=_('方案讨论'))
    # initiation_data = models.OneToOneField(to=ProjectInitiationData, null=True, on_delete=models.SET_NULL, blank=True,
    #                                        verbose_name=_('立项资料'))

    sponsor_nmpa_submission_date = models.DateField(
        verbose_name=_("申办方向国家药监局递交临床实验申请日期"),
        null=True,
        blank=True,
        default=None,
    )
    site_application_receipt_date = models.DateField(
        verbose_name=_("临床试验机构收到立项申请日期"),
        null=True,
        blank=True,
        default=None,
    )
    site_approval_date = models.DateField(
        verbose_name=_("临床试验机构立项日期"), null=True, blank=True, default=None
    )
    created_at = models.DateField(verbose_name=_("创建时间"), auto_now_add=True)
    updated_at = models.DateField(verbose_name=_("修改时间"), auto_now=True)

    agent_users = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        blank=True,
        related_name='represent_projects',
        verbose_name=_("代理用户"),
        help_text=_("代理用户可以替你填写项目信息")
    ) 

    audit_management = GenericRelation(
        AuditManagement,
        content_type_field='content_type',
        object_id_field='object_id',
        verbose_name=_("审核管理")
    )

    @property
    def am_info(self):
        if not self.pk:
            raise Exception("Should save project object first to gain a pk/id.")
        ams = AuditManagement.objects.filter(tags__name=f"project-{self.pk}").select_related('content_type')
        return self._am_info(ams)

    def _am_info(self, ams):
        am_map = dict.fromkeys(MODEL_AUDIT_PROGRESS_ORDER)
        min_progress, max_progress = 0, 0
        ams = sorted(ams, key=sort_am_progress_key_fn)
        for cls_name, cls_progress in MODEL_AUDIT_PROGRESS_MAP.items():
            while len(ams):
                am = ams[0]
                am_cls_name = am.content_type.model_class().__name__
                cls_status = am_map.get(cls_name, None)
                if am_cls_name != cls_name:
                    if cls_status == AUDIT_STATUS.APPROVED:
                        max_progress = cls_progress
                        if cls_progress - min_progress == 1:
                            min_progress += 1
                    break

                
                # approved > pending > rejected
                if am.status == AUDIT_STATUS.APPROVED:
                    am_map[cls_name] = am.status
                elif am.status == AUDIT_STATUS.REJECTED:
                    if cls_status is None:
                        am_map[cls_name] = am.status
                else: # am.status == AUDIT_STATUS.PENDING:
                    if cls_status is None or cls_status != AUDIT_STATUS.APPROVED:
                        am_map[cls_name] = am.status
                
                ams.pop(0)

            if len(ams) == 0:
                cls_status = am_map.get(cls_name, None)
                cls_progress = MODEL_AUDIT_PROGRESS_MAP[cls_name]
                if cls_status == AUDIT_STATUS.APPROVED:
                    max_progress = cls_progress
                    if cls_progress - min_progress == 1:
                        min_progress += 1
        
        return (min_progress, max_progress, ), am_map
        

    def can_view(self, user):
        return (
            self.creator == user
            or self.agent_users.filter(id=user.id).exists()
            or user.has_perms(["user.can_manage_projects"])
        )

    def can_edit(self, user):
        return (
            self.creator == user
            or self.agent_users.filter(id=user.id).exists()
            or user.has_perms(["user.can_manage_projects"])
        )
    

    class Meta:
        default_permissions=[]
        db_table = "project"
        verbose_name = _("项目信息")
        verbose_name_plural = verbose_name

        
    @classmethod
    def get_link(cls, id):
        return reverse("project:detail", kwargs={'pk': id})


# we use `str` type key due to we import other model class in `.` directory will introduce
# circular import issue
MODEL_AUDIT_PROGRESS_ORDER = [
    'Project',
    'Plan',
    'InitiationData',
    'BeforeImplement',
    'Implement',
    'Finish'
]

MODEL_AUDIT_PROGRESS_MAP = {
    model_name: idx + 1 
    for idx, model_name in enumerate(MODEL_AUDIT_PROGRESS_ORDER)
}

def sort_am_progress_key_fn(am: AuditManagement):
    cls_name = am.content_type.model_class().__name__
    try:
        return MODEL_AUDIT_PROGRESS_MAP[cls_name]
    except KeyError:
        raise Exception(f"{cls_name} shouldn't use `project-{{}}` as its AuditManagment tag!")
